const path = require('path')
const fs = require('fs-extra')
const { execFile } = require('child_process')
const logger = require('./logger')
const config = require('./config')

class DocxConverter {
    /**
     * 在路径的最后一个目录前插入目标目录
     * @param {string} originalPath 原始路径
     * @param {string} targetDir 要插入的目标目录名（默认'target'）
     * @returns {string} 处理后的新路径
     */
    insertDirectoryBeforeLast(originalPath, targetDir = 'target') {
        // logger.info(`insertDirectoryBeforeLast: ${originalPath}`)
        // 处理空路径
        if (!originalPath) return targetDir;

        // 判断是否以分隔符结尾
        const endsWithSlash = /[\\/]$/.test(originalPath);

        // 标准化处理：
        // 1. 去除首尾多余分隔符
        // 2. 统一转成正斜杠
        const normalized = originalPath
            .replace(/^[\\/]+/, '')
            .replace(/[\\/]+$/, '')
            .replace(/[\\/]+/g, '/');

        // 拆分路径部分
        const parts = normalized.split('/');

        // 插入目标目录
        if (parts.length === 0) {
            parts.push(targetDir);
        } else {
            const insertPos = parts.length - 1;
            parts.splice(insertPos, 0, targetDir);
        }

        // 重组路径并恢复结尾分隔符
        let newPath = parts.join('/');
        if (endsWithSlash) newPath += '/';

        // 还原Windows路径分隔符（可选）
        if (originalPath.includes('\\')) {
            newPath = newPath.replace(/\//g, '\\');
        }

        return newPath;
    }
    /**
     * 确保路径以 target/ 开头，自动补充缺失的 target 目录
     * @param {string} originalPath - 原始路径
     * @returns {string} 标准化后的路径
     */
    normalizeTargetPath(originalPath, targetDir = config.media.dirName) {
     
        // 处理空路径直接返回 target
    if (!originalPath) return targetDir;

    // 记录原始路径是否以分隔符结尾
    const endsWithSlash = /[\\/]$/.test(originalPath);

    // 标准化步骤：
    // 1. 统一转成正斜杠
    // 2. 去除首尾多余分隔符
    const normalized = originalPath
        .replace(/\\/g, '/')                // 统一正斜杠
        .replace(/^\/+/, '')                // 去除开头斜杠
        .replace(/\/+$/, '')                // 去除结尾斜杠
        .replace(/\/+/g, '/');              // 合并连续斜杠
    // 找到文件层级索引值 为了后续找到图片的层级
    const index = normalized.split('/').findIndex(item => item === targetDir);
    let finalPath = normalized

    if(index > -1) {
        const pre = '../'.repeat(index);
        finalPath = `${pre}${targetDir}/${normalized}`
    }

    // 恢复原始路径分隔符格式
    if (originalPath.includes('\\')) {
        finalPath = finalPath.replace(/\//g, '\\');
    }

    // 恢复结尾分隔符状态
    return endsWithSlash ? finalPath + originalPath.slice(-1) : finalPath;
    }
    getMediaDir() {
        // 直接使用输出目录下的media文件夹
        // logger.info(`this.outputDir: ${this.outputDir}`)
        return path.join(this.outputDir, config.media.dirName)
    }
    constructor(inputDir, outputDir) {
    this.inputDir = path.resolve(inputDir)
    this.outputDir = path.resolve(outputDir)
    this.stats = { total: 0, success: 0, failed: 0 }
    }

    // === 主运行方法 ===
    async run() {
    try {
        await this.validatePaths()
        await this.prepareOutput()
        await this.processDirectory(this.inputDir)
        this.showSummary()
    } catch (err) {
        logger.error(`运行失败: ${err.message}`)
        process.exit(1)
    }
    }

    // === 核心方法 ===

    // 验证路径有效性
    async validatePaths() {
    if (!(await fs.pathExists(this.inputDir))) {
        throw new Error(`输入目录不存在: ${this.inputDir}`)
    }
    if (path.relative(this.inputDir, this.outputDir) === '') {
        throw new Error('输入目录和输出目录不能相同')
    }
    }

    // 准备输出目录
    async prepareOutput() {
    await fs.ensureDir(this.outputDir)
    // logger.info(`输出目录已创建: ${this.outputDir}`)
    }

    // 递归处理目录
    async processDirectory(currentDir) {
    const entries = await fs.readdir(currentDir, { withFileTypes: true })

    for (const entry of entries) {
        const srcPath = path.join(currentDir, entry.name)
        const relativePath = path.relative(this.inputDir, srcPath)
        const destPath = path.join(this.outputDir, relativePath)

        if (entry.isDirectory()) {
        await this.processDirectory(srcPath)
        } else if (this.isDocxFile(entry.name)) {
        await this.convertFile(srcPath, destPath)
        }
    }
    }

    // === 文件转换方法 ===

    // 判断是否为DOCX文件
    isDocxFile(filename) {
    return path.extname(filename).toLowerCase() === '.docx'
    }
    // 新增表格后处理方法
    async postProcessTables(mdPath) {
        let content = await fs.readFile(mdPath, 'utf8')
    
        // 修复旧版本缺少的表格分隔符
        content = content.replace(
            /^([|][^\n]+\n)(?![-|])/gm,
            (match, header) => {
                const cols = header.split('|').length - 1
                const divider = '|' + Array(cols).join('---|') + '\n'
                return header + divider
            }
        )
        
        // 移除旧版本多余的表格对齐符号
        content = content.replace(/[:]-+/g, '---')
        
        // 移除多余的转义字符
        // content = content.replace(/\\\|/g, '|')
        logger.info(`content: ${content}`)
        
        await fs.writeFile(mdPath, content)
    }
    // 执行文件转换
    async convertFile(inputPath, outputPath) {
        // logger.info(`inputPath: ${inputPath}`)
        this.stats.total++
        const mdPath = outputPath.replace(/\.docx$/i, '.md')
        // logger.info(`mdPath: ${mdPath}`)
        try {
            // logger.fileStatus(path.relative(this.inputDir, inputPath), 'converting')
            
            // 确保目标目录存在
            await fs.ensureDir(path.dirname(mdPath))
            const relativeDir = path.relative(this.inputDir, inputPath.replace('.docx', '').replace(/\s/g, "_"))
            const mediaDir = path.join(
                this.outputDir,
                config.media.dirName,
                relativeDir
            )
        //    logger.info(`relativeDir: ${relativeDir}`)
           
            // const tableArgs = [
            //     '-f', 'docx',
            //     '-t', 'markdown+pipe_tables',
            //     '--columns=200',
            //     '--wrap=preserve',
            //     '--table-striped-tables',
            //     '--markdown-headings=atx'
            // ]
            // 旧版本专用参数
            // const legacyTableArgs = [
            //     '-f', 'docx',
            //     '-t', 'markdown+pipe_tables',     // 强制管道表格
            //     '--columns=80',                   // 旧版本最大有效列宽
            //     '--wrap=none',                      // 禁用自动换行（旧版本关键参数）
            //     '--strict',                        // 禁用Markdown扩展语法
            // ]
            const fixedTableArgs = [
                '-f', 'docx',
                '-t', 'markdown+pipe_tables',
                '--columns=120',
                '--wrap=none',                  // 修正的换行参数
                '--markdown-headings=atx',      // 替代--strict的功能
                '--resource-path=.:media'       // 确保资源路径正确
            ]
 
            // 构建Pandoc参数 '--toc'
            const args = [
                // ...fixedTableArgs, 
                inputPath,
                '-o', mdPath, '--toc', 
                `--extract-media=${mediaDir}`, // [!code focus]
                ...config.pandoc.baseArgs
            ]
            // 确保媒体目录存在 [!code focus]
            await fs.ensureDir(mediaDir)
            // logger.info(`媒体目录：${mediaDir}`)
            // logger.info(`媒体目录mdPath：${mdPath}`)
            // 执行转换
            await this.execPandoc(args)
            
            // 修正图片路径
            await this.fixImagePaths(mdPath, mediaDir)
            // 添加表格后处理
            await this.postProcessTables(mdPath)
            
            this.stats.success++
            // logger.fileStatus(path.relative(this.inputDir, inputPath), 'success')
        } catch (err) {
            this.stats.failed++
            logger.fileStatus(path.relative(this.inputDir, inputPath), 'failed')
            logger.error(`转换失败: ${err.message}`)
        }
    }

    // 执行Pandoc命令
    async execPandoc(args) {
    return new Promise((resolve, reject) => {
        const child = execFile('pandoc', args, (error, stdout, stderr) => {
        if (error) {
            error.message += `\nPandoc错误输出: ${stderr}`
            return reject(error)
        }
        resolve()
        })

        // 设置超时
        child.timeout = config.pandoc.timeout
        child.on('timeout', () => {
        child.kill()
        reject(new Error(`转换超时 (${config.pandoc.timeout}ms)`))
        })
    })
    }


    // 修改 fixImagePaths 方法签名，添加 mediaDir 参数
    async fixImagePaths(mdPath, mediaDir) {
        const content = await fs.readFile(mdPath, 'utf8')
        const mdDir = path.dirname(mdPath)
      
        // 使用更精确的正则匹配图片路径
        const fixedContent = content.replace(/!\[(.*?)\]\((.*?)\)/g, (match, altText, imgPath) => {
          // 处理Pandoc生成的嵌套media目录
          const actualImagePath = path.join(mediaDir, imgPath)
          
          // 计算相对路径时考虑多级目录
          const relativePath = path.relative(mdDir, actualImagePath)
          
          // 特殊处理Windows路径
          return `![](${this.normalizeImagePath(relativePath)})`
        })
      
        await fs.writeFile(mdPath, fixedContent)
      }
      
      // 专用图片路径标准化方法
      normalizeImagePath(p) {
        const path = p.replace(/\\/g, '/')          // 统一正斜杠
               .replace(/^\.\//, '')         // 去除开头的./
               .replace(/(%20)/g, ' ')       // 解码空格
               .replace(/%25/g, '%')         // 解码双重编码的%
               .replace(/\/+/g, '/')         // 合并连续斜杠
            //    logger.warn(`relPath:${path}`)
       const result = this.insertDirectoryBeforeLast(path, config.media.dirName)
       return result;       
    }

    // 简化路径标准化方法
    normalizePath(p) {
        return p.replace(/\\/g, '/')          // 统一正斜杠
            .replace(/\/+/g, '/')         // 合并连续斜杠
            .replace(/^\.\//, '')        // 去除开头的./
            .replace(/(%20)/g, ' ')      // 解码空格
            .replace(/%25/g, '%')       // 解码双重编码的%
    }
    // 显示统计信息
    showSummary() {
    logger.success(`
    转换完成!
    ┌────────────┬─────────┐
    │ 总文件数   │ ${this.stats.total.toString().padEnd(7)} │
    ├────────────┼─────────┤
    │ 成功转换   │ ${this.stats.success.toString().padEnd(7)} │
    ├────────────┼─────────┤
    │ 转换失败   │ ${this.stats.failed.toString().padEnd(7)} │
    └────────────┴─────────┘
    `)

    if (this.stats.failed > 0) {
        logger.warn('失败文件处理建议：\n1. 检查文件是否损坏\n2. 确认不是加密文档\n3. 尝试手动转换失败文件')
    }
    }
}

module.exports = DocxConverter